#include "database.h"

#include <QSqlQuery>

#include "data.h"

QSqlDatabase Database::m_db;

void Database::openDatabase()
{
    m_db = QSqlDatabase::addDatabase("QSQLITE"); // SQLite 3.36
    m_db.setDatabaseName("../res/data.db");
    if (m_db.open())
    {
        qInfo() << "Opened database.";
    }
    else
    {
        qWarning() << "Open database failed.";
    }
}

void Database::closeDatabase()
{
    m_db.close();
    if (!m_db.isOpen())
    {
        qInfo() << "Closed database.";
    }
    else
    {
        qWarning() << "Close database failed.";
    }
}

void Database::loadMissions()
{
    QSqlQuery query("SELECT * FROM missions ORDER BY launch_time DESC;");

    while (query.next())
    {
        int missionId = query.value("id").toInt();

        QSqlQuery queryUniquePoint;
        queryUniquePoint.prepare("SELECT name,"
                                 "       time"
                                 "  FROM unique_point"
                                 " WHERE mission_id == :id"
                                 " ORDER BY time;");
        queryUniquePoint.bindValue(":id", missionId);
        queryUniquePoint.exec();
        QList<std::tuple<QString, double>> uniquePoint;
        while (queryUniquePoint.next())
        {
            uniquePoint.append(std::make_tuple(queryUniquePoint.value("name").toString(),
                                               queryUniquePoint.value("time").toDouble()));
        }

        QSqlQuery queryTaskSegment;
        queryTaskSegment.prepare("SELECT stations.name AS station_name,"
                                 "       equipments.name AS equipment_name,"
                                 "       start_time,"
                                 "       stop_time"
                                 "  FROM task_segment,"
                                 "       stations,"
                                 "       equipments"
                                 " WHERE task_segment.mission_id == :id AND "
                                 "       stations.id == task_segment.station_id AND "
                                 "       equipments.id == task_segment.equipment_id"
                                 " ORDER BY start_time;");
        queryTaskSegment.bindValue(":id", missionId);
        queryTaskSegment.exec();
        QList<std::tuple<QString, QString, double, double>> taskSegment;
        while (queryTaskSegment.next())
        {
            taskSegment.append(std::make_tuple(queryTaskSegment.value("station_name").toString(),
                                               queryTaskSegment.value("equipment_name").toString(),
                                               queryTaskSegment.value("start_time").toDouble(),
                                               queryTaskSegment.value("stop_time").toDouble()));
        }

        const_cast<QList<Mission>&>(Data::missions)
            .append(Mission(query.value("id").toInt(),
                            query.value("brief").toString(),
                            query.value("code").toString(),
                            query.value("mark").toString(),
                            query.value("rocket_model").toString(),
                            query.value("coordinate").toString(),
                            query.value("method").toString(),
                            query.value("launch_point").toString(),

                            query.value("launch_azimuth").toDouble(),
                            query.value("launch_longitude").toDouble(),
                            query.value("launch_latitude").toDouble(),
                            query.value("launch_altitude").toDouble(),

                            QDateTime::fromSecsSinceEpoch(query.value("launch_time").toLongLong()),
                            uniquePoint,
                            taskSegment));
    }
}

void Database::loadStations()
{
    QSqlQuery query("SELECT * FROM stations;");

    while (query.next())
    {
        const_cast<QList<Station>&>(Data::stations)
            .append(Station(query.value("name").toString(),
                            query.value("longitude").toDouble(),
                            query.value("latitude").toDouble()));
    }
}

void Database::loadEquipmentData(int missionId)
{
    const_cast<QList<EquipmentData>&>(Data::equipmentData).clear();

    QSqlQuery queryEquipmentData;
    queryEquipmentData.prepare("SELECT equipments.name AS equipment_name,"
                               "       stations.name AS station_name,"
                               "       T,"
                               "       A,"
                               "       E,"
                               "       AGC,"
                               "       SNR"
                               "  FROM equipment_data,"
                               "       equipments,"
                               "       task_segment,"
                               "       stations"
                               " WHERE equipment_data.mission_id == :id AND "
                               "       equipment_data.mission_id == task_segment.mission_id AND "
                               "       equipment_data.equipment_id == equipments.id AND "
                               "       task_segment.station_id == stations.id AND "
                               "       equipments.id == task_segment.equipment_id"
                               " ORDER BY equipment_data.equipment_id;");
    queryEquipmentData.bindValue(":id", missionId);
    queryEquipmentData.exec();

    while (queryEquipmentData.next())
    {
        const_cast<QList<EquipmentData>&>(Data::equipmentData)
            .append(EquipmentData(queryEquipmentData.value("equipment_name").toString(),
                                  queryEquipmentData.value("station_name").toString(),
                                  queryEquipmentData.value("T").toDouble(),
                                  queryEquipmentData.value("A").toDouble(),
                                  queryEquipmentData.value("E").toDouble(),
                                  queryEquipmentData.value("AGC").toDouble(),
                                  queryEquipmentData.value("SNR").toDouble()));
    }
}
